<template>
	<div class="container">
		<template>
			<div class="catalogue">
				<button class="new_chat" @click="addNewConversation">新建对话</button>
				<div class="history">
					<span class="item_name">历史记录 ──────────</span>
					<div class="rec_list">
						<div :class="['record', { active: conversation_id === item.id }]" @click="handleClickHistory(item)" v-for="item in historyList" :key="item.id">{{ item.name }}</div>
					</div>
				</div>
			</div>
			<div class="list">
				<div v-if="!dataList.length" class="default_info">
					<img class="ai_img" src="../../assets/img/icon-ai.png" />
					<span class="name">警官，你好！</span>
					<span class="tips">智案精灵，你的案情分析助手</span>
				</div>
				<Conversation ref="chatWrapperRef" :dataList="dataList" :errorFlag="errorFlag" :stopFlag="stopFlag"
					@sendMessage="search">
				</Conversation>
				<div class="chat_bg">
					<textarea v-model="keywords" class="input" @keyup.enter="search()"></textarea>
					<img @click="search()" class="send_icon" src="../../assets/img/send.png" />
				</div>
			</div>
		</template>

	</div>
</template>

<script>
import Conversation from './components/Conversation.vue'
import axios from 'axios';
import { postFetch, baseURL, token, fetchURl } from '@/api/_fetch'
import { getCurrentFormattedTime, escapeHtml, unicodeToChar } from '@/libs/aiMethods'
export default {
	components: {
		Conversation
	},
	data() {
		return {
			keywords: '',//关键词
			dataList: [], // 对话数据
			historyList: [], // 历史列表
			errorFlag: -1,
			stopFlag: false,
			conversation_id: '', // 会话id
			abortController: null,
			signal: null,
			currentAnswerText: '',
			chatInfo: {
				historyId: '',
				taskId: '',
				message_id: '',
				created_at: '',
			},
			intervalTimer: null,
			reader: null,
			userId: '', // 当前登录的用户id
		};
	},
	mounted() {
		this.userId = JSON.parse(localStorage.getItem('userInfo'))?.sysUserInfo.id;
		this.getHistoryList()
	},
	methods: {
		// 初始化各种数据状态
		init() {
			this.keywords = ''
			this.dataList = []
			this.conversation_id = ''
		},
		// 获取历史会话列表
		getHistoryList() {
			axios.get(fetchURl.conversations, {
				params: {
					user: this.userId
				},
				baseURL,
				headers: {
					Authorization: token
				},
			}).then(res => {
				if (res.status === 200) {
					const { data } = res.data;
					this.historyList = data
				}
			})
		},
		// 点击历史会话
		handleClickHistory(item) {
			if (this.conversation_id === item.id) return
			this.conversation_id = item.id
			this.getMessageList()
		},
		// 获取当前点击的会话列表
		getMessageList() {
			axios.get(fetchURl.messages, {
				params: {
					user: this.userId,
					conversation_id: this.conversation_id
				},
				baseURL,
				headers: {
					Authorization: token
				},
			}).then(res => {
				if (res.status === 200) {
					const { data } = res.data;
					this.dataList = data.map(item => {
						item.isCollapse = true
						return item
					});
					setTimeout(() => {
						this.$refs.chatWrapperRef.setScrollTop()
					}, 20)
				}
			})
		},
		// 新建对话
		addNewConversation() {
			if (this.stopFlag) {
				this.$message({
					type: 'warning',
					message: '智案精灵正在会话中，请等待当前会话完成再进行操作'
				})
				return
			}
			this.init()
		},
		search(keyword) {
			if (this.stopFlag) {
				this.$message({
					type: 'warning',
					message: '智案精灵正在会话中，请等待当前会话完成再进行操作'
				})
				return
			}
			this.keywords = keyword || this.keywords
			this.stopFlag = true
			setTimeout(() => {
				this.$refs.chatWrapperRef.setScrollTop()
			}, 20)
			this.dataList.push({
				conversation_id: this.conversation_id || '',
				query: this.keywords.replace(/\n/g, '<br/>'),
				answer: '',
				time: getCurrentFormattedTime(),
				isCollapse: true,
				message_files: []
			})
			const params = {
				auto_generate_name: true,
				conversation_id: this.conversation_id || '',
				query: this.keywords,
				files: [],
				inputs: {},
				response_mode: 'streaming',
				user: this.userId
			}
			this.abortController = new AbortController()
			if ('signal' in this.abortController) {
				this.signal = this.abortController?.signal
			}
			this.keywords = ''
			const lastIndex = this.dataList.length - 1;
			postFetch(fetchURl.screenStreamChat, params).then(async response => {
				
				if (response.body?.locked) {
					console.log('流已经被一个读取器锁定。')
					return
				}
				if (!response.body) throw Error('No response from server')
				await this.handleStream(response, lastIndex, this.$refs.chatWrapperRef)
				this.getHistoryList()

				this.conversation_id = this.dataList[0].conversation_id
			}).finally(() => {
				this.stopFlag = false
			})
		},
		/**
		 * 处理数据流
		 * @param response
		 * @param setScrollTop
		 * @param isFile 是否是文档解读
		 */
		async handleStream(response, lastIndex, setScrollTop) {
			this.reader = response.body?.getReader();
			const decoder = new TextDecoder('utf-8');
			let isEnd = false;
			let buffer = '';
			let bufferObj = {};
			while (!isEnd) {
				try {
					const { value, done: doneing } = await this.reader.read();
					isEnd = doneing;
					buffer += decoder.decode(value, { stream: true });
					const lines = buffer.split('\n');
					for (let i = 0; i < lines.length - 1; i++) {
						const message = lines[i];
						if (message.startsWith('data: ')) {
							const trimmedMessage = message.substring("data: ".length).trim();
							if (trimmedMessage) {
								try {
									bufferObj = JSON.parse(trimmedMessage);
								} catch (e) {
									continue;
								}
								if (bufferObj.event === 'message' || bufferObj.event === 'agent_message') {
									const text = escapeHtml(unicodeToChar(bufferObj.answer));
									this.currentAnswerText += text
									this.dataList[lastIndex].conversation_id = bufferObj.conversation_id;
									this.chatInfo.taskId = bufferObj.task_id;
									this.chatInfo.message_id = bufferObj.message_id;
									this.chatInfo.created_at = ~~bufferObj.created_at || Date.now();
								}
								else if (bufferObj.event === 'message_end') {
									isEnd = true;
								}
								else if (bufferObj.event === 'error') {
									this.errorFlag = lastIndex;
									isEnd = true;
								}
							}
						}
					}
					buffer = lines[lines.length - 1];
					if (!isEnd) {
						this.typewriterEffect(setScrollTop);
					} else {
						break;
					}
				} catch (e) {
					console.error('Error in handleStream:', e);
					isEnd = true;
					return;
				}
			}
		},
		// 打字机效果
		typewriterEffect() {
			let charIndex = 0
			if (this.intervalTimer) return
			this.intervalTimer = setInterval(() => {
				if (charIndex < this.currentAnswerText.length) {
					this.dataList[this.dataList.length - 1]['answer'] += this.currentAnswerText.charAt(charIndex)
					charIndex++
					setTimeout(() => {
						this.$refs.chatWrapperRef.setScrollTop()
					}, 60)
				} else {
					this.currentAnswerText = ''
					clearInterval(this.intervalTimer)
					this.intervalTimer = null
				}

			}, 10) // 调整打字速度，单位为毫秒
		},
		// 中断请求
		// abortPostFetch(index) {
		// 	if (this.abortController) {
		// 		clearInterval(this.intervalTimer)
		// 		this.intervalTimer = null
		// 		if (index == 1) {
		// 			this.chatInfo.taskId &&
		// 				stopConversation({
		// 					task_id: this.chatInfo.taskId
		// 				}).then(() => {
		// 					this.reader.cancel()
		// 					this.abortController.abort()
		// 				})
		// 		}
		// 		this.intervalTimer = null
		// 		this.abortController = null
		// 		this.signal = null
		// 		this.stopFlag = false
		// 	}
		// }
	},
};
</script>

<style lang="scss" scoped>
.container {
	display: flex;
}

.catalogue {
	box-sizing: border-box;
	position: relative;
	width: 280px;
	padding: 20px;
	margin: 15px 0px 12px 12px;
	max-height: calc(100% - 60px);
	background: rgba(255, 255, 255, 0.502);
	border-radius: 8px 8px 8px 8px;
	border: 2px solid #FFFFFF;
	overflow: auto;

	.new_chat {
		background-color: #4575f6;
		color: white;
		width: 100%;
		padding: 10px;
		border-radius: 8px 8px 8px 8px;
		border: 2px solid #FFFFFF;
		cursor: pointer;
	}

	.history {
		margin-top: 20px;
		display: flex;
		flex-direction: column;
		height: calc(100% - 70px);
		.item_name {
			font-size: 16px;
			font-weight: bold;
			color: gray;
		}

		.rec_list {
			flex: 1;
			margin-top: 20px;
			display: flex;
			flex-direction: column;
			overflow-y: auto;

			.record {
				color: black;
				font-size: 12px;
				cursor: pointer;
				padding: 10px 5px;
				border-radius: 20px;
				&:hover, &.active {
					background-color: #4575f6;
					color: white;
				}
			}
		}
	}
}


.list {
	box-sizing: border-box;
	position: relative;
	flex: 1;
	padding: 20px;
	margin: 15px 12px 12px;
	max-height: calc(100% - 60px);
	background: rgba(255, 255, 255, 0.502);
	border-radius: 8px 8px 8px 8px;
	border: 2px solid #FFFFFF;
	display: flex;
	flex-direction: column;
	justify-content: space-between;
	.default_info {
		display: flex;
		flex-direction: column;
		justify-content: center;
		align-items: center;

		.ai_img {
			margin-top: 65px;
			width: 80px;
			height: 80px;
		}

		.name {
			margin-top: 10px;
			font-size: 26px;
			font-weight: bold;
			color: black;
		}

		.tips {
			margin-top: 15px;
			font-size: 14px;
			color: black;
		}
	}

	.chat_bg {
		justify-content: flex-end;
		align-items: flex-end;
		border: 1px solid #CCC;
		display: flex;
		flex-direction: row;
		padding: 10px;
		align-items: center;
		background-color: white;
		border-radius: 10px;

		.input {
			flex: 1;
			height: 50px;
			border: none;
			resize: none;
		}

		.send_icon {
			width: 40px;
			height: 40px;
			margin-left: 10px;
			margin-right: 10px;
			cursor: pointer;
		}
	}
}
</style>
